package rs.arm.letthemusicplay;

import java.io.IOException;
import java.util.ArrayList;

import rs.arm.letthemusicplay.utilities.Constants;
import rs.arm.letthemusicplay.utilities.FileUtilities;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

public class MediaPlayerService extends Service implements MediaPlayer.OnPreparedListener,
		MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener,
		AudioManager.OnAudioFocusChangeListener {

	private static String TAG_PLAYER_SERVICE = "MediaPlayerService";
	LocalBroadcastManager broadcastManager = null;
	// TODO prebaciti u onCreate
	private MediaPlayer mPlayer = null;
	private AudioManager aManager = null;
	private String songPath = "..."; // TODO change this
	private String songName = "..."; // TODO change this
	private Handler handler = new Handler();
	private ArrayList<String> playlist = new ArrayList<String>();
	private ArrayList<String> favoritesPlaylist = new ArrayList<String>();
	private int currentSong = 0;
	private boolean isShuffle = false;
	private boolean isRepeat = false;
	private boolean isPaused = false;

	private Context mContext;
	private BroadcastReceiver receiver;

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent != null) {
			mContext = getApplicationContext();
			favoritesPlaylist = FileUtilities.getFavoritesPlaylist();
			broadcastManager = LocalBroadcastManager.getInstance(mContext);
			receiver = new PlayerBroadcastReceiver();
			mContext.registerReceiver(receiver, new IntentFilter(
					Constants.ACTION_ACTIVITY_TO_PLAYER_SERVICE));
			playlist = intent.getStringArrayListExtra(Constants.EXTRA_PLAY_LIST);
			setPlayerRunning(0);
		}
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		if (mPlayer != null) {
			mPlayer.release();
		}
		mContext.unregisterReceiver(receiver);
		super.onDestroy();
	}

	@Override
	public void onPrepared(MediaPlayer mp) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean onError(MediaPlayer mp, int what, int extra) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
		if (isRepeat) {
			setPlayerRunning(currentSong);
		} else if (isShuffle) {
			currentSong = (int) (Math.random() * (playlist.size() + 1));
			setPlayerRunning(currentSong);
		} else {
			playNextSong();
		}
	}

	@Override
	public void onAudioFocusChange(int focusChange) {
		switch (focusChange) {
		case AudioManager.AUDIOFOCUS_GAIN:
			// resume playback
			if (mPlayer == null) {
				initMediaPlayer(Constants.ERROR_CODE);
			} else if (!mPlayer.isPlaying()) {
				mPlayer.start();
			}
			mPlayer.setVolume(1.0f, 1.0f);
			break;

		case AudioManager.AUDIOFOCUS_LOSS:
			// Lost focus for an unbounded amount of time: stop playback and
			// release media player
			if (mPlayer.isPlaying()) {
				mPlayer.stop();
			}
			mPlayer.release();
			mPlayer = null;
			break;

		case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
			// Lost focus for a short time, but we have to stop
			// playback. We don't release the media player because playback
			// is likely to resume
			if (mPlayer.isPlaying()) {
				mPlayer.pause();
			}
			break;

		case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
			// Lost focus for a short time, but it's ok to keep playing
			// at an attenuated level
			if (mPlayer.isPlaying()) {
				mPlayer.setVolume(0.1f, 0.1f);
			}
			break;
		}
	}

	private void initMediaPlayer(int num) {
		if (num != Constants.ERROR_CODE) {
			songPath = playlist.get(num);
			songName = songPath.substring(songPath.lastIndexOf("/") + 1);
			currentSong = num;
		}
		if (mPlayer == null) {
			mPlayer = new MediaPlayer();
		}
		mPlayer.setOnCompletionListener(this);
		try {
			mPlayer.reset();
			mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mPlayer.setDataSource(songPath);
			mPlayer.prepare();
			mPlayer.start();
		} catch (IOException e) {
			Log.e(TAG_PLAYER_SERVICE, e.getMessage());
		}
	}

	private void primarySeekBarProgressUpdater() {
		int currentSeek = (int) (((float) mPlayer.getCurrentPosition() / mPlayer.getDuration()) * 100);
		sendMessageToActivity(Integer.toString(currentSeek), Constants.SEND_UPDATE_SEEKBAR);
		if (mPlayer.isPlaying()) {
			Runnable notification = new Runnable() {
				public void run() {
					primarySeekBarProgressUpdater();
					setCurentDuration(mPlayer.getCurrentPosition());
				}
			};
			handler.postDelayed(notification, 1000);
		}
	}

	private void sendMessageToActivity(String msg, int code) {
		if (msg == null) {
			return;
		}
		Intent intent = new Intent(Constants.PLAYER_SERVICE_RESULT);
		switch (code) {
		case Constants.SEND_UPDATE_SEEKBAR:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_SEEKBAR);
			intent.putExtra(Constants.MSG_UPDATE_SEEKBAR, msg);
			break;
		case Constants.SEND_UPDATE_DURATION_1:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_DURATION_1);
			intent.putExtra(Constants.MSG_UPDATE_DURATION_1, msg);
			break;
		case Constants.SEND_UPDATE_DURATION_2:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_DURATION_2);
			intent.putExtra(Constants.MSG_UPDATE_DURATION_2, msg);
			break;
		case Constants.SEND_UPDATE_SONG_TITLE:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_SONG_TITLE);
			intent.putExtra(Constants.MSG_UPDATE_SONG_TITLE, msg);
			break;
		case Constants.SEND_UPDATE_SONG_STAR:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_SONG_STAR);
			intent.putExtra(Constants.MSG_UPDATE_STAR, msg);
			break;
		case Constants.SEND_UPDATE_STAR:
			intent.putExtra(Constants.CODE_UPDATE, Constants.SEND_UPDATE_STAR);
			intent.putExtra(Constants.MSG_UPDATE_STAR, msg);
			break;
		}
		broadcastManager.sendBroadcast(intent);
	}

	public void setCurentDuration(int sec) {
		sec = sec / 1000;
		int min = sec / 60;
		sec = sec % 60;
		String dur = min + ":" + sec;
		sendMessageToActivity(dur, Constants.SEND_UPDATE_DURATION_1);
	}

	public void setSongDuration() {
		int sec = mPlayer.getDuration();
		sec = sec / 1000;
		int min = sec / 60;
		sec = sec % 60;
		String dur = min + ":" + sec;
		sendMessageToActivity(dur, Constants.SEND_UPDATE_DURATION_2);
	}

	private void setPlayerRunning(int num) {
		if (mPlayer == null) {
			initMediaPlayer(num);
		} else {
			if (mPlayer.isPlaying()) {
				try {
					mPlayer.stop();
					mPlayer.reset();
					mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
					songPath = playlist.get(num);
					if (favoritesPlaylist.contains(songPath)) {
						sendMessageToActivity(Constants.MSG_UPDATE_TRUE, Constants.SEND_UPDATE_STAR);
					}
					mPlayer.setDataSource(songPath);
					mPlayer.prepare();
					mPlayer.start();
				} catch (Exception e) {
					Log.e(TAG_PLAYER_SERVICE, e.getMessage());
				}
			} else if (isPaused) {
				isPaused = false;
				mPlayer.start();
			}
		}
		setSongDuration();
		primarySeekBarProgressUpdater();
		sendMessageToActivity(songName, Constants.SEND_UPDATE_SONG_TITLE);
	}

	private void pauseSong(){
		if(mPlayer.isPlaying()){
			mPlayer.pause();
			isPaused = true;
		}
	}

	private void playNextSong() {
		currentSong++;
		if (currentSong > playlist.size()) {
			currentSong = 0;
		}
		setPlayerRunning(currentSong);
		drawStar();
	}

	private void playPreviousSong() {
		currentSong--;
		if (currentSong == -1) {
			currentSong = playlist.size();
		}
		setPlayerRunning(currentSong);
		drawStar();
	}

	private void starButtonClicked() {
		// star update is in main activity in this case
		if (favoritesPlaylist.contains(songPath)) {
			favoritesPlaylist.remove(songPath);
			sendMessageToActivity(Constants.MSG_UPDATE_FALSE, Constants.SEND_UPDATE_SONG_STAR);
		} else {
			favoritesPlaylist.add(songPath);
			sendMessageToActivity(Constants.MSG_UPDATE_TRUE, Constants.SEND_UPDATE_SONG_STAR);
		}
	}

	private void drawStar() {
		if (favoritesPlaylist.contains(songPath)) {
			favoritesPlaylist.remove(songPath);
			sendMessageToActivity(Constants.MSG_UPDATE_FALSE, Constants.SEND_UPDATE_STAR);
		} else {
			favoritesPlaylist.add(songPath);
			sendMessageToActivity(Constants.MSG_UPDATE_TRUE, Constants.SEND_UPDATE_STAR);
		}
	}

	private void playFavorites() {
		playlist.clear();
		playlist.addAll(favoritesPlaylist);
		currentSong = 0;
		setPlayerRunning(currentSong);
	}

	private void unpauseSong() {
		isPaused = true;
		mPlayer.start();
		primarySeekBarProgressUpdater();
	}

	public class PlayerBroadcastReceiver extends BroadcastReceiver {

		public PlayerBroadcastReceiver() {
			super();
		}

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (!action.equals(Constants.ACTION_ACTIVITY_TO_PLAYER_SERVICE)) {
				return;
			}
			Bundle extras = intent.getExtras();
			if (extras != null) {
				int code = intent.getIntExtra(Constants.CODE_ACTION, Constants.ERROR_CODE);
				switch (code) {
				case Constants.ACTION_BTN_PLAY:
					pauseSong();
					break;
				case Constants.ACTION_BTN_PAUSE:
					unpauseSong();
					break;
				case Constants.ACTION_BTN_NEXT:
					playNextSong();
					break;
				case Constants.ACTION_BTN_PREVIOUS:
					playPreviousSong();
					break;
				case Constants.ACTION_BTN_REPEAT:
					isRepeat = !isRepeat;
					break;
				case Constants.ACTION_BTN_SHUFFLE:
					isShuffle = !isShuffle;
					break;
				case Constants.ACTION_ADD_NEW_SONG:
					String songName = intent.getStringExtra(Constants.EXTRA_SONG_NAME);
					playlist.add(songName);
					break;
				case Constants.ACTION_STAR_CLICKED:
					starButtonClicked();
					break;
				case Constants.ACTION_DRAW_STAR:
					drawStar();
					break;
				case Constants.ACTION_PLAY_FAVORITES:
					playFavorites();
					break;
				case Constants.ACTION_REMOVE_FROM_PLAYLIST:
					playlist.remove(currentSong);
					currentSong--; // TODO see how this works if it's first song
					break;
				}
			}
		}
	}
}
